package com.game.core.dbwrite.server;

import java.util.concurrent.ScheduledThreadPoolExecutor;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.game.core.dbwrite.constant.CacheOperationType;
import com.game.core.dbwrite.constant.DBOperationType;
import com.game.core.dbwrite.domain.MemoryCache;
import com.game.core.dbwrite.domain.QueueCache;
import com.game.core.dbwrite.domain.Storage;
import com.game.core.dbwrite.task.DirectWriteToDBUtil;
import com.game.core.dbwrite.task.MemoryWriteToMysqlTask;
import com.game.core.dbwrite.task.MemoryWriteToRocksDBTask;
import com.game.core.dbwrite.task.QueueCacheWriteToMysqlTask;
import com.game.core.dbwrite.task.RocksDBWriteToMysqlTask;
import com.game.core.dbwrite.task.TaskExecutor;
import com.game.core.dbwrite.util.KryoUtil;

// 提供操作数据库的接口
public class DBService
{
	private static Logger logger = LoggerFactory.getLogger(DBService.class);
	private static DBService service = null;
	private static CacheOperationType cacheType = CacheOperationType.MEMORY_ONLY;
	
	private static ScheduledThreadPoolExecutor rocksDBWriteToMysqlTaskExecutor = null;
	private static ScheduledThreadPoolExecutor memoryWriteToMysqlTaskExecutor = null;
	private static ScheduledThreadPoolExecutor memoryWriteToRocksDBTaskExecutor = null;
	private static ScheduledThreadPoolExecutor queueCacheWriteToMysqlTaskExecutor = null;

	private DBService()
	{
	}

	public static DBService getInstance()
	{
		if (service == null)
		{
			synchronized (DBService.class)
			{
				if (service == null)
				{
					service = new DBService();
				}
			}
		}
		return service;
	}

	public int getDBMemoryCacheTaskCount()
	{
		return MemoryCache.getDBMemoryCacheTaskCount();
	}

	// 设置缓存使用方式，ROCKSDB_ONLY，MEMORY_ONLY，MEMORY_ROCKSDB,QUEUE_CACHE,NONE
	public void setCacheOperationType(CacheOperationType type)
	{
		cacheType = type;
	}

	// 设置向MySQL数据库更新时间
	public void setRocksDBToMysqlUpdateTime(long time)
	{
		if (time > 0 && time < 10000)
			DBServiceParemeter.rocksDBToMysqlUpdateTime = time;
	}

	public void setMemoryToMysqlUpdateTime(long time)
	{
		if (time > 0 && time < 50000)
			DBServiceParemeter.memoryToMysqlUpdateTime = time;
	}

	public void setMemoryToRocksDBUpdateTime(long time)
	{
		if (time > 0 && time < 50000)
			DBServiceParemeter.memoryToRocksDBUpdateTime = time;
	}

	public void setQueueCacheToMysqlUpdateTime(long time)
	{
		if (time > 0 && time < 50000)
			DBServiceParemeter.queueCacheToMysqlUpdateTime = time;
	}

	public void insert(long beanNum, Class<?> clazz, Object obj)
	{
		switch (cacheType)
		{
		case ROCKSDB_ONLY:
			Storage.addToList(beanNum, clazz, DBOperationType.INSERT, KryoUtil.serilize(clazz, obj));
			break;
		case MEMORY_ONLY:
			MemoryCache.addToMap(beanNum, clazz, DBOperationType.INSERT, KryoUtil.serilize(clazz, obj));
			break;
		case MEMORY_ROCKSDB:
			MemoryCache.addToMap(beanNum, clazz, DBOperationType.INSERT, KryoUtil.serilize(clazz, obj));
			break;
		case QUEUE_CACHE:
			QueueCache.add(beanNum, clazz, DBOperationType.INSERT, KryoUtil.serilize(clazz, obj));
			break;
		case DIRECT_DB:
			DirectWriteToDBUtil.directWriteTODB(clazz, DBOperationType.INSERT, obj);
			break;
		case NONE:
			break;
		}
	}

	public void update(long beanNum, Class<?> clazz, Object obj)
	{
		beanNum += 1;
		switch (cacheType)
		{
		case ROCKSDB_ONLY:
			Storage.addToList(beanNum, clazz, DBOperationType.UPDATE, KryoUtil.serilize(clazz, obj));
			break;
		case MEMORY_ONLY:
			MemoryCache.addToMap(beanNum, clazz, DBOperationType.UPDATE, KryoUtil.serilize(clazz, obj));
			break;
		case MEMORY_ROCKSDB:
			MemoryCache.addToMap(beanNum, clazz, DBOperationType.UPDATE, KryoUtil.serilize(clazz, obj));
			break;
		case QUEUE_CACHE:
			QueueCache.add(beanNum, clazz, DBOperationType.UPDATE, KryoUtil.serilize(clazz, obj));
			break;
		case DIRECT_DB:
			DirectWriteToDBUtil.directWriteTODB(clazz, DBOperationType.UPDATE, obj);
			break;
		case NONE:
			break;
		}
	}

	public void delete(long beanNum, Class<?> clazz, Object obj)
	{
		beanNum += 2;
		switch (cacheType)
		{
		case ROCKSDB_ONLY:
			Storage.addToList(beanNum, clazz, DBOperationType.DELETE, KryoUtil.serilize(clazz, obj));
			break;
		case MEMORY_ONLY:
			MemoryCache.addToMap(beanNum, clazz, DBOperationType.DELETE, KryoUtil.serilize(clazz, obj));
			break;
		case MEMORY_ROCKSDB:
			MemoryCache.addToMap(beanNum, clazz, DBOperationType.DELETE, KryoUtil.serilize(clazz, obj));
			break;
		case QUEUE_CACHE:
			QueueCache.add(beanNum, clazz, DBOperationType.DELETE, KryoUtil.serilize(clazz, obj));
			break;
		case DIRECT_DB:
			DirectWriteToDBUtil.directWriteTODB(clazz, DBOperationType.DELETE, obj);
			break;
		case NONE:
			break;
		}
	}

	/**
	 *	DB Task 启动方法 
	 */
	public void startWriteDBTask()
	{
		switch (cacheType)
		{
		case ROCKSDB_ONLY:
			RocksDBWriteToMysqlTask rocksDBWriteToDBTask = new RocksDBWriteToMysqlTask();
			rocksDBWriteToMysqlTaskExecutor = TaskExecutor.startTask(rocksDBWriteToDBTask, 0, DBServiceParemeter.rocksDBToMysqlUpdateTime);
			break;
		case MEMORY_ONLY:
			MemoryWriteToMysqlTask memeryWriteToDBTask = new MemoryWriteToMysqlTask();
			memoryWriteToMysqlTaskExecutor = TaskExecutor.startTask(memeryWriteToDBTask, 0, DBServiceParemeter.memoryToMysqlUpdateTime);
			break;
		case MEMORY_ROCKSDB:
			MemoryWriteToRocksDBTask memoryWriteToRocksDBTask = new MemoryWriteToRocksDBTask();
			memoryWriteToRocksDBTaskExecutor = TaskExecutor.startTask(memoryWriteToRocksDBTask, 0, DBServiceParemeter.memoryToRocksDBUpdateTime);

			RocksDBWriteToMysqlTask rocksDBWriteToMysqlDBTask = new RocksDBWriteToMysqlTask();
			rocksDBWriteToMysqlTaskExecutor = TaskExecutor.startTask(rocksDBWriteToMysqlDBTask, 0, DBServiceParemeter.rocksDBToMysqlUpdateTime);
			break;
		case QUEUE_CACHE:
			QueueCacheWriteToMysqlTask queueCacheWriteToMysqlTask = new QueueCacheWriteToMysqlTask();
			queueCacheWriteToMysqlTaskExecutor = TaskExecutor.startTask(queueCacheWriteToMysqlTask, 0, DBServiceParemeter.queueCacheToMysqlUpdateTime);
			break;
		case NONE:
		case DIRECT_DB:
			break;
		}
	}

	protected void waiting(long waitingTime)
	{
		try
		{
			Thread.sleep(waitingTime);
		}
		catch (Exception e)
		{
			logger.error("exception :", e);
		}
	}

	// 关闭写数据库的任务，调用该方法时会阻塞当前线程直到缓存中的数据全部写入MySQL中。
	public void endWriteDBTask()
	{
		switch (cacheType)
		{
		case ROCKSDB_ONLY:
			while (!Storage.isRocksDBFinishedWriting())
			{
				waiting(1000);
			}
			Storage.closeRocksDB();
			TaskExecutor.endTask(rocksDBWriteToMysqlTaskExecutor);
			break;
		case MEMORY_ONLY:
			while (!MemoryCache.isMemoryFinishedWriting())
			{
				waiting(1000);
			}
			TaskExecutor.endTask(memoryWriteToMysqlTaskExecutor);
			break;
		case MEMORY_ROCKSDB:
			while (!MemoryCache.isMemoryFinishedWriting() || !Storage.isRocksDBFinishedWriting())
			{
				waiting(1000);
			}
			Storage.closeRocksDB();
			TaskExecutor.endTask(memoryWriteToRocksDBTaskExecutor);
			TaskExecutor.endTask(rocksDBWriteToMysqlTaskExecutor);
			break;
		case QUEUE_CACHE:
			while (!QueueCache.isQueueCacheFinishedWriting())
			{
				waiting(1000);
			}
			TaskExecutor.endTask(queueCacheWriteToMysqlTaskExecutor);
			break;
		case NONE:
		case DIRECT_DB:
			break;
		}
	}
}